// 重试机制工具
import { errorHandler, ErrorType, ErrorSeverity } from './errorHandler'

// 重试配置接口
export interface RetryConfig {
    maxAttempts: number
    baseDelay: number
    maxDelay: number
    backoffFactor: number
    retryCondition?: (error: unknown) => boolean
    onRetry?: (attempt: number, error: unknown) => void
    onMaxRetriesReached?: (error: unknown) => void
}

// 默认重试配置
const DEFAULT_RETRY_CONFIG: RetryConfig = {
    maxAttempts: 3,
    baseDelay: 1000,
    maxDelay: 10000,
    backoffFactor: 2,
    retryCondition: (error) => {
        // 默认只重试网络错误和超时错误
        if (error instanceof Error) {
            const message = error.message.toLowerCase()
            return message.includes('network') ||
                message.includes('timeout') ||
                message.includes('fetch') ||
                message.includes('connection')
        }
        return false
    }
}

// 重试状态跟踪
interface RetryState {
    attempt: number
    lastError: unknown
    startTime: number
    totalDelay: number
}

// 重试管理器类
export class RetryManager {
    private activeRetries = new Map<string, RetryState>()

    // 执行带重试的异步操作
    async executeWithRetry<T>(
        operation: () => Promise<T>,
        config: Partial<RetryConfig> = {},
        operationId?: string
    ): Promise<T> {
        const finalConfig = { ...DEFAULT_RETRY_CONFIG, ...config }
        const id = operationId || this.generateOperationId()

        const state: RetryState = {
            attempt: 0,
            lastError: null,
            startTime: Date.now(),
            totalDelay: 0
        }

        this.activeRetries.set(id, state)

        try {
            return await this.attemptOperation(operation, finalConfig, state, id)
        } finally {
            this.activeRetries.delete(id)
        }
    }

    // 尝试执行操作
    private async attemptOperation<T>(
        operation: () => Promise<T>,
        config: RetryConfig,
        state: RetryState,
        operationId: string
    ): Promise<T> {
        while (state.attempt < config.maxAttempts) {
            state.attempt++

            try {
                const result = await operation()

                // 成功时记录恢复信息
                if (state.attempt > 1) {
                    errorHandler.handleError(new Error('Operation recovered after retries'), {
                        type: ErrorType.NETWORK_ERROR,
                        severity: ErrorSeverity.LOW,
                        context: {
                            operationId,
                            attempts: state.attempt,
                            totalTime: Date.now() - state.startTime,
                            totalDelay: state.totalDelay
                        },
                        showNotification: false,
                        logToConsole: true
                    })
                }

                return result
            } catch (error) {
                state.lastError = error

                // 检查是否应该重试
                if (!config.retryCondition || !config.retryCondition(error)) {
                    throw error
                }

                // 如果是最后一次尝试，抛出错误
                if (state.attempt >= config.maxAttempts) {
                    if (config.onMaxRetriesReached) {
                        config.onMaxRetriesReached(error)
                    }

                    errorHandler.handleError(error, {
                        type: ErrorType.NETWORK_ERROR,
                        severity: ErrorSeverity.HIGH,
                        context: {
                            operationId,
                            maxAttemptsReached: true,
                            totalAttempts: state.attempt,
                            totalTime: Date.now() - state.startTime
                        }
                    })

                    throw error
                }

                // 计算延迟时间
                const delay = this.calculateDelay(state.attempt, config)
                state.totalDelay += delay

                // 调用重试回调
                if (config.onRetry) {
                    config.onRetry(state.attempt, error)
                }

                // 记录重试信息
                errorHandler.handleError(error, {
                    type: ErrorType.NETWORK_ERROR,
                    severity: ErrorSeverity.LOW,
                    context: {
                        operationId,
                        retryAttempt: state.attempt,
                        nextRetryIn: delay,
                        maxAttempts: config.maxAttempts
                    },
                    showNotification: false,
                    logToConsole: true
                })

                // 等待后重试
                await this.delay(delay)
            }
        }

        throw state.lastError
    }

    // 计算延迟时间（指数退避）
    private calculateDelay(attempt: number, config: RetryConfig): number {
        const exponentialDelay = config.baseDelay * Math.pow(config.backoffFactor, attempt - 1)
        const jitteredDelay = exponentialDelay * (0.5 + Math.random() * 0.5) // 添加抖动
        return Math.min(jitteredDelay, config.maxDelay)
    }

    // 延迟函数
    private delay(ms: number): Promise<void> {
        return new Promise(resolve => setTimeout(resolve, ms))
    }

    // 生成操作ID
    private generateOperationId(): string {
        return `retry_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`
    }

    // 获取活动重试状态
    getActiveRetries(): Map<string, RetryState> {
        return new Map(this.activeRetries)
    }

    // 取消特定重试
    cancelRetry(operationId: string): boolean {
        return this.activeRetries.delete(operationId)
    }

    // 取消所有重试
    cancelAllRetries(): void {
        this.activeRetries.clear()
    }
}

// 导出单例实例
export const retryManager = new RetryManager()

// 便捷的重试函数
export const withRetry = <T>(
    operation: () => Promise<T>,
    config?: Partial<RetryConfig>
): Promise<T> => {
    return retryManager.executeWithRetry(operation, config)
}

// 预定义的重试配置
export const RetryConfigs = {
    // 网络请求重试
    NETWORK_REQUEST: {
        maxAttempts: 3,
        baseDelay: 1000,
        maxDelay: 5000,
        backoffFactor: 2,
        retryCondition: (error: unknown) => {
            if (error instanceof Error) {
                const message = error.message.toLowerCase()
                return message.includes('network') ||
                    message.includes('timeout') ||
                    message.includes('fetch') ||
                    message.includes('connection') ||
                    message.includes('ECONNRESET') ||
                    message.includes('ETIMEDOUT')
            }
            return false
        }
    } as Partial<RetryConfig>,

    // 文件上传重试
    FILE_UPLOAD: {
        maxAttempts: 5,
        baseDelay: 2000,
        maxDelay: 30000,
        backoffFactor: 1.5,
        retryCondition: (error: unknown) => {
            if (error instanceof Error) {
                const message = error.message.toLowerCase()
                return message.includes('upload') ||
                    message.includes('network') ||
                    message.includes('timeout')
            }
            return false
        }
    } as Partial<RetryConfig>,

    // 影像加载重试
    IMAGE_LOAD: {
        maxAttempts: 2,
        baseDelay: 500,
        maxDelay: 2000,
        backoffFactor: 2,
        retryCondition: (error: unknown) => {
            if (error instanceof Error) {
                const message = error.message.toLowerCase()
                return message.includes('load') ||
                    message.includes('network') ||
                    message.includes('fetch')
            }
            return false
        }
    } as Partial<RetryConfig>,

    // API调用重试
    API_CALL: {
        maxAttempts: 3,
        baseDelay: 1000,
        maxDelay: 8000,
        backoffFactor: 2,
        retryCondition: (error: unknown) => {
            // 只重试5xx服务器错误和网络错误
            if (error && typeof error === 'object' && 'status' in error) {
                const status = (error as any).status
                return status >= 500 || status === 0 // 0表示网络错误
            }
            if (error instanceof Error) {
                const message = error.message.toLowerCase()
                return message.includes('network') ||
                    message.includes('timeout') ||
                    message.includes('server')
            }
            return false
        }
    } as Partial<RetryConfig>
}

// 带重试的API调用包装器
export const withApiRetry = <T>(
    apiCall: () => Promise<T>,
    customConfig?: Partial<RetryConfig>
): Promise<T> => {
    const config = { ...RetryConfigs.API_CALL, ...customConfig }
    return withRetry(apiCall, config)
}

// 带重试的文件上传包装器
export const withUploadRetry = <T>(
    uploadOperation: () => Promise<T>,
    customConfig?: Partial<RetryConfig>
): Promise<T> => {
    const config = { ...RetryConfigs.FILE_UPLOAD, ...customConfig }
    return withRetry(uploadOperation, config)
}

// 带重试的影像加载包装器
export const withImageLoadRetry = <T>(
    loadOperation: () => Promise<T>,
    customConfig?: Partial<RetryConfig>
): Promise<T> => {
    const config = { ...RetryConfigs.IMAGE_LOAD, ...customConfig }
    return withRetry(loadOperation, config)
}

// 电路断路器模式实现
export class CircuitBreaker {
    private failures = 0
    private lastFailureTime = 0
    private state: 'CLOSED' | 'OPEN' | 'HALF_OPEN' = 'CLOSED'

    constructor(
        private failureThreshold: number = 5,
        private recoveryTimeout: number = 60000, // 1分钟
        private monitoringPeriod: number = 120000 // 2分钟
    ) { }

    async execute<T>(operation: () => Promise<T>): Promise<T> {
        if (this.state === 'OPEN') {
            if (Date.now() - this.lastFailureTime > this.recoveryTimeout) {
                this.state = 'HALF_OPEN'
            } else {
                throw new Error('Circuit breaker is OPEN - operation not allowed')
            }
        }

        try {
            const result = await operation()
            this.onSuccess()
            return result
        } catch (error) {
            this.onFailure()
            throw error
        }
    }

    private onSuccess(): void {
        this.failures = 0
        this.state = 'CLOSED'
    }

    private onFailure(): void {
        this.failures++
        this.lastFailureTime = Date.now()

        if (this.failures >= this.failureThreshold) {
            this.state = 'OPEN'

            errorHandler.handleError(new Error('Circuit breaker opened due to repeated failures'), {
                type: ErrorType.NETWORK_ERROR,
                severity: ErrorSeverity.HIGH,
                context: {
                    failures: this.failures,
                    threshold: this.failureThreshold,
                    state: this.state
                }
            })
        }
    }

    getState(): { state: string; failures: number; lastFailureTime: number } {
        return {
            state: this.state,
            failures: this.failures,
            lastFailureTime: this.lastFailureTime
        }
    }

    reset(): void {
        this.failures = 0
        this.lastFailureTime = 0
        this.state = 'CLOSED'
    }
}

// 导出默认电路断路器实例
export const defaultCircuitBreaker = new CircuitBreaker()